package com.kly.sc.api.application.service.user.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.exception.common.ApplicationException;
import com.google.common.collect.Lists;
import com.kly.dto.Benefit;
import com.kly.dto.ProductBenefitDto;
import com.kly.dto.ReduceBenefitsDto;
import com.kly.dto.UserVasPurchasesDto;
import com.kly.enums.Benefits;
import com.kly.enums.ProductCategory;
import com.kly.sc.api.application.enums.BenefitsType;
import com.kly.sc.api.application.helper.RequestLocalInfo;
import com.kly.sc.api.application.service.user.BenefitService;
import com.kly.sc.api.application.service.user.HasMemberBenefitsValidationService;
import com.kly.sc.api.application.service.utils.BaseComponent;
import com.kly.sc.api.application.utils.RpcUtils;
import com.kly.sc.api.application.vo.BenefitDto;
import com.kly.sc.api.application.vo.ChatDataDto;
import com.kly.sc.api.application.vo.MemberBenefits;
import com.kly.sc.api.application.vo.UserBenefit;
import com.kly.service.ProductService;
import com.kly.service.UserVasPurchasesService;
import com.kly.user.dto.SumUserMsgDto;
import com.kly.user.dto.UserBaseDto;
import com.kly.user.dto.UserConversationRecordDto;
import com.kly.user.dto.UserMsgDto;
import com.kly.user.enums.ConversationType;
import com.kly.user.service.AuthLoginService;
import com.kly.user.service.UserConversationService;
import com.kly.user.service.UserMsgService;
import com.kly.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Slf4j
@Service
public class HasMemberBenefitsValidationServiceImpl implements HasMemberBenefitsValidationService {

    @Resource
    UserVasPurchasesService userVasPurchasesService;
    @Resource
    UserConversationService userConversationService;
    @Resource
    UserMsgService userMsgService;
    @Resource
    UserService userService;
    @Resource
    BenefitService benefitService;
    @Resource
    AuthLoginService authLoginService;
    /**
     * 单会话消息上限
     */
    @NacosValue(value = "${single.message.max.num:100}", autoRefreshed = true)
    private Integer singleMessageMaxNum;
    /**
     * 破冰会话消息条数闽值
     */
    @NacosValue(value = "${single.message.first.chat.num:1}", autoRefreshed = true)
    private Integer singleFirstChatMessageNum;
    /**
     * 有效会话消息条数闽值
     */
    @NacosValue(value = "${single.message.valid.chat.num:5}", autoRefreshed = true)
    private Integer singleValidChatMessageMaxNum;
    /**
     * 深度会话消息条数闽值
     */
    @NacosValue(value = "${single.message.first.chat.num:30}", autoRefreshed = true)
    private Integer singleDeepChatMessageMaxNum;
    /**
     * 会话限制配置
     */
    @NacosValue(value = "${chat.config}", autoRefreshed = true)
    private String chatConfig;

    @NacosValue(value = "${white.list}", autoRefreshed = true)
    private String whiteList;

    @Override
    public Boolean hasSingleBenefits(Benefits benefitsType, String userCode) {
        if (StringUtils.isBlank(userCode)) {
            return Boolean.FALSE;
        }

        List<Benefits> benefits = Lists.newArrayList();
        benefits.add(benefitsType);
        final List<MemberBenefits> memberBenefits = hasBenefits(benefits, userCode);
        log.info("==== hasSingleBenefits, userCode:{}, benefitsTypes:{}, queryResult:{}",
                userCode, JSONObject.toJSONString(benefits), JSONUtil.toJsonPrettyStr(memberBenefits));
        if (CollectionUtils.isEmpty(memberBenefits)) {
            return null;
        }
        final MemberBenefits MemberBenefitsByBenefitsType = memberBenefits.get(0);
        return MemberBenefitsByBenefitsType.getHasBenefits();

    }


    @Override
    public List<MemberBenefits> hasBenefits(List<Benefits> benefitsTypes, String userCode) {
        if (StringUtils.isBlank(userCode)) {
            return null;
        }
        if(CollectionUtils.isEmpty(benefitsTypes)) {
            benefitsTypes = Benefits.getAllBenefits();
        }

        final List<Integer> benefitsCodes = benefitsTypes.parallelStream().map(Benefits::getBenefitCode).collect(Collectors.toList());

        final List<UserVasPurchasesDto> userVasPurchasesDtos = RpcUtils.getResult(userVasPurchasesService.getAllUserBenefits(userCode));
        log.info("==== queryUserBenefitsResult, userCode:{}, benefitsTypes:{}, queryResult:{}",
                userCode, JSONObject.toJSONString(benefitsTypes), JSONUtil.toJsonPrettyStr(userVasPurchasesDtos));
        if (CollectionUtils.isEmpty(userVasPurchasesDtos)) {
            return null;
        }

        Predicate<UserVasPurchasesDto> isExistsPredicate = dto -> benefitsCodes.contains(dto.getBenefitCode());

        final List<MemberBenefits> memberBenefits = userVasPurchasesDtos.parallelStream().filter(isExistsPredicate).map(benefitsDetail -> {
            Integer additionNum = Objects.isNull(benefitsDetail.getAdditionalBenefitCount()) ? 0 : benefitsDetail.getAdditionalBenefitCount();
            int totalBenefitsNum = benefitsDetail.getUsageCount() + additionNum;
            if (totalBenefitsNum > 0) {
                return buildMemberBenefitsDto(benefitsDetail, Boolean.TRUE);
            } else {
                return buildMemberBenefitsDto(benefitsDetail, Boolean.FALSE);
            }
        }).collect(Collectors.toList());

        log.info("==== memberBenefits, userCode:{}, benefitsTypes:{}, queryResult:{}", userCode, JSONObject.toJSONString(benefitsTypes), JSONUtil.toJsonPrettyStr(memberBenefits));
        return memberBenefits;
    }

    @Override
    public Integer queryBenefitsByUserCode(Benefits benefitsType, String userCode) {
        if (StringUtils.isBlank(userCode)) {
            return 0;
        }

        final List<UserVasPurchasesDto> userVasPurchasesDtos = RpcUtils.getResult(userVasPurchasesService.getAllUserBenefits(userCode));
        log.info("==== queryUserBenefitsResult, userCode:{}, queryResult:{}", userCode, JSONObject.toJSONString(userVasPurchasesDtos));
        if (CollectionUtils.isEmpty(userVasPurchasesDtos)) {
            return 0;
        }
        final UserVasPurchasesDto userVasPurchasesDto = userVasPurchasesDtos.parallelStream()
                .filter(o -> Objects.equals(benefitsType.getBenefitCode(), o.getBenefitCode()))
                .findFirst().orElse(null);
        if (Objects.isNull(userVasPurchasesDto)) {
            return 0;
        }
        return checkAndReturn(userVasPurchasesDto.getUsageCount()) + checkAndReturn(userVasPurchasesDto.getAdditionalBenefitCount());
    }


    @Override
    public void updateAllBenefitsForUser(String fromUserCode, String toUserCode, List<UserMsgDto> todayMessages) {

        for (UserMsgDto dto : todayMessages) {
            if (dto.getMsgNum() > ConversationType.FIRST_CONVERSATION.getSize()) {
                reduceBenefit(fromUserCode, toUserCode, ConversationType.FIRST_CONVERSATION, Benefits.ICE_BREAKING_SESSION);
                storeConversationRecords(fromUserCode, toUserCode,  ConversationType.FIRST_CONVERSATION, Integer.valueOf(String.valueOf(dto.getMsgNum())));
            }
            if (dto.getMsgNum() > ConversationType.EFFECTIVE_CONVERSATIONS.getSize()) {
                reduceBenefit(fromUserCode, toUserCode, ConversationType.EFFECTIVE_CONVERSATIONS, Benefits.EFFECTIVE_SESSION);
                storeConversationRecords(fromUserCode, toUserCode,  ConversationType.EFFECTIVE_CONVERSATIONS, Integer.valueOf(String.valueOf(dto.getMsgNum())));
            }
            if (dto.getMsgNum() > ConversationType.DEEP_CONVERSATIONS.getSize()) {
                reduceBenefit(fromUserCode, toUserCode, ConversationType.DEEP_CONVERSATIONS, Benefits.DEEP_SESSION);
                storeConversationRecords(fromUserCode, toUserCode,  ConversationType.DEEP_CONVERSATIONS, Integer.valueOf(String.valueOf(dto.getMsgNum())));
            }
            if (dto.getMsgNum() > ConversationType.HUNDRED_CONVERSTIONS.getSize()) {
                reduceBenefit(fromUserCode, toUserCode, ConversationType.HUNDRED_CONVERSTIONS, Benefits.SESSION_MESSAGE_LIMIT);
                storeConversationRecords(fromUserCode, toUserCode, ConversationType.HUNDRED_CONVERSTIONS, Integer.valueOf(String.valueOf(dto.getMsgNum())));
            }
        }

    }

    private void reduceBenefit(String fromUserCode, String toUserCode, ConversationType conversationType, Benefits benefits) {
        final long startTime = System.currentTimeMillis();
        final Boolean isExistsRecord = (Boolean) RpcUtils.getResult(userConversationService.isExists(fromUserCode, toUserCode, conversationType.getCode()));
        if (!isExistsRecord) {
            ReduceBenefitsDto reduceBenefits = new ReduceBenefitsDto();
            reduceBenefits.setUserCode(fromUserCode);
            reduceBenefits.setBenefitCode(benefits.getBenefitCode());
            userVasPurchasesService.reduceUserBenefits(reduceBenefits);
        }
    }

    private void storeConversationRecords(String fromUserCode, String toUserCode, Integer totalMsgNum, BenefitDto chatNumConfig) {
        // 单段会话第100条记录会话
        if (totalMsgNum >= chatNumConfig.getOverLimitChat()) {
            log.info("storeOverLimitChat, userCode:{}, toUserCode:{}, totalMsgNum:{}", fromUserCode, toUserCode,  totalMsgNum);
            storeConversationRecords(fromUserCode, toUserCode,  ConversationType.HUNDRED_CONVERSTIONS, totalMsgNum);
        }
        // 单段会话第31条记录深度会话
        if (totalMsgNum > singleDeepChatMessageMaxNum) {
            log.info("storeDeepChat, userCode:{}, toUserCode:{}, totalMsgNum:{}", fromUserCode, toUserCode, totalMsgNum);
            storeConversationRecords(fromUserCode, toUserCode, ConversationType.DEEP_CONVERSATIONS, totalMsgNum);
        }
        // 单段会话第6条消息记当有效会话
        if (totalMsgNum > singleValidChatMessageMaxNum) {
            log.info("storeValidChat, userCode:{}, toUserCode:{}, totalMsgNum:{}", fromUserCode, toUserCode, totalMsgNum);
            storeConversationRecords(fromUserCode, toUserCode, ConversationType.EFFECTIVE_CONVERSATIONS, totalMsgNum);
        }
        // 单段会话第二条消息记录为破冰会话
        if (totalMsgNum > singleFirstChatMessageNum) {
            log.info("storeFirstChat, userCode:{}, toUserCode:{}, totalMsgNum:{}", fromUserCode, toUserCode, totalMsgNum);
            storeConversationRecords(fromUserCode, toUserCode, ConversationType.FIRST_CONVERSATION, totalMsgNum);
        }
    }

    @Override
    public Integer getRemainSendMessageNum(String fromUserCode, String toUserCode) {
        // 单段会话消息总数
        int totalMsgNum = getMessageCount(fromUserCode, toUserCode);

        // 当日会话情况
//        final List<UserMsgDto> todayMessages = userMsgService.selectTodayMessages(fromUserCode, null, 0);
//        if (CollectionUtils.isEmpty(todayMessages)) {
//            return singleMessageMaxNum;
//        }

        // 获取会话配置
//        final BenefitDto chatNumConfig = getChatNumConfig(fromUserCode);
        final BenefitDto chatNumConfig = benefitService.getChatChatBenefit(fromUserCode,  RequestLocalInfo.getRequestBasicInfo().getAppCode());

        // 会话记录
        final long startTime = System.currentTimeMillis();
        storeConversationRecords(fromUserCode, toUserCode, totalMsgNum, chatNumConfig);
        log.info("===storeConversationRecords==fromUser:{}, toUser:{}, costTime:{}", fromUserCode, toUserCode, System.currentTimeMillis() - startTime);

        // 计算剩余发送消息数
        final List<ChatDataDto> sumUserMsgDtos = getSumUserMsgDtos(fromUserCode);
        ChatSumHelper chatSumHelper = new ChatSumHelper(sumUserMsgDtos, totalMsgNum, toUserCode, chatNumConfig);

        log.info("获取剩余发送消息数：{}",JSONObject.toJSONString(chatSumHelper));
        return chatSumHelper.getRemainCount(chatNumConfig);

    }

    private BenefitDto getChatNumConfig(String userCode) {
        final String appCode = RequestLocalInfo.getRequestBasicInfo().getAppCode();
        final ProductCategory productCategory = benefitService.getProductCategory(userCode, appCode);
        final UserBenefit chatBenefitConfig = benefitService.getSessionConfig(appCode);
        if (ProductCategory.NEW_USER_BENEFITS.equals(productCategory)) {
            return chatBenefitConfig.getNewUserBenefit();
        }
        // meboo 3.0版本：用户注销后重新注册，
        return chatBenefitConfig.getOldUserBenefit();
    }


    /**
     * 获取有效的权益次数
     * @param userVasPurchasesDto
     * @return
     */
    private int sumAdditionalBenefitCount(UserVasPurchasesDto userVasPurchasesDto) {

        //判断是否有赠送权益次数
        if(userVasPurchasesDto.getAdditionalBenefitCount() != null){
            //判断是否在有效期内或者是没有期限的
            if( userVasPurchasesDto.getAdditionalStartDate() ==null||(DateUtil.between(userVasPurchasesDto.getAdditionalStartDate(),new Date(), DateUnit.SECOND) >0 &&
                    DateUtil.between(new Date(),userVasPurchasesDto.getAdditionalEndDate(), DateUnit.SECOND) >0)){
                return userVasPurchasesDto.getAdditionalBenefitCount();
            }else{
                return 0;
            }
        }

        return 0;
    }

    public static cn.hutool.json.JSONObject sumChatConfigAndUserUsage(cn.hutool.json.JSONObject chatConfig, int deepUsage, int effectiveUsage, int iceBreakingUsage) {


        chatConfig.put("firstChatLimitNum",chatConfig.getInt("firstChatLimitNum")+iceBreakingUsage);
        chatConfig.put("effectiveChatLimitNum",chatConfig.getInt("effectiveChatLimitNum")+effectiveUsage);
        chatConfig.put("deepChatLimitNum",chatConfig.getInt("deepChatLimitNum")+deepUsage);
        return chatConfig;


    }

    private List<ChatDataDto> getSumUserMsgDtos(String fromUserCode) {
        final List<SumUserMsgDto> sumUserMsgDtos = userMsgService.listUserMsgByFromUserCode(fromUserCode, null, 0);
        if (CollectionUtils.isEmpty(sumUserMsgDtos)) {
            return Lists.newArrayList();
        }
        return sumUserMsgDtos.parallelStream().map(
                o -> ChatDataDto.builder().toUserCode(o.getToUserCode()).hasSendMsgNum(o.getMsgNum()).build())
            .collect(Collectors.toList());
    }


    @Override
    public List<MemberBenefits> hasAllBenefits(String userCode) {
        return hasBenefits(null,userCode);
    }

    private MemberBenefits buildMemberBenefitsDto(UserVasPurchasesDto benefitsDetail, Boolean hasBenefitsFlag) {
        return MemberBenefits.builder().hasBenefits(hasBenefitsFlag).benefitsType(Benefits.fromType(benefitsDetail.getBenefitCode())).build();
    }

    private Integer checkAndReturn(Integer usageCount) {
        return Objects.isNull(usageCount) ? 0 : usageCount;
    }

    private int getMessageCount(String fromUserCode, String toUserCode) {
        UserMsgDto userMsg = userMsgService.getUserMsgNum(fromUserCode, toUserCode);
        if (userMsg == null) {
            return 0;
        }
        return userMsg.getMsgNum();
    }

    private void storeConversationRecords(String userCode, String toUserCode, ConversationType conversationType, Integer msgNum) {
        final long startTime = System.currentTimeMillis();
        UserConversationRecordDto conversationRecord =
                UserConversationRecordDto.builder().userCode(userCode).toUserCode(toUserCode)
                        .conversationsAttributes(conversationType.getCode()).conversationsNumber(msgNum)
                        .conversationsType(conversationType.getCode()).build();
        userConversationService.addUserConversation(conversationRecord);
        log.info("==storeConversationRecords==userCode:{}, toUserCode:{}, type:{}, msgNum:{}, costTime:{}", userCode, toUserCode, conversationType.getCode(), msgNum, System.currentTimeMillis() - startTime);
    }


}
